#include "ShaderParser.h"
#include "..\utils\PlainTextReader.h"
#include "..\utils\Log.h"
#include "..\content\ResManager.h"
#include "..\base\Engine.h"
#include "..\content\Shader.h"
#include "..\content\Material.h"

namespace ds {

void ShaderDecl::createResource() {
	LOGC(logINFO,"ShaderDecl") << "create resource - material " << m_Material;
	ResourceHandle materialHandle = gEngine->getResourceManager().findByName(m_Material.c_str(),RS_MATERIAL);	
	LOGC(logINFO,"ShaderDecl") << "resource handle " << materialHandle.m_Type;
	//if ( gEngine->getResourceManager().getMaterialByName(m_Material.c_str()) == 0 ) {
	if ( materialHandle.m_Type == RS_INVALID ) {
		LOGC(logINFO,"ShaderDecl") << "Material not found - creating new one";
		if ( !m_Texture.empty() ) {
			LOGC(logINFO,"ShaderDecl") << "Creating new material with given texture " << m_Texture;
			materialHandle = gEngine->getResourceManager().createMaterial(m_Material.c_str(),m_Texture.c_str(),true);
		}
		else {
			LOGC(logINFO,"ShaderDecl") << "Creating new material";
			materialHandle = gEngine->getResourceManager().createMaterial(m_Material.c_str());
		}
	}
	ResourceHandle shaderHandle = gEngine->getResourceManager().loadShader(m_Name.c_str(),m_File.c_str(),m_Technique.c_str());		
	gEngine->getResourceManager().assignShader(shaderHandle,materialHandle);
	Shader& shader = gEngine->getResourceManager().getShader(shaderHandle);
	for ( size_t i = 0; i < m_Parameters.size(); ++i ) {
		ResourceDeclaration* rd = m_Parameters[i];
		if ( rd->getType() == DT_FLOAT ) {
			FloatDecl* fd = static_cast<FloatDecl*>(rd);
			shader.setFloat(fd->getName(),fd->getValue());
		}
		else if ( rd->getType() == DT_VEC3 ) {
			Vec3Decl* fd = static_cast<Vec3Decl*>(rd);
			shader.setVec3(fd->getName(),fd->getValue());				
		}
		else if ( rd->getType() == DT_COLOR ) {
			ColorDecl* cd = static_cast<ColorDecl*>(rd);
			shader.setColor(cd->getName(),cd->getValue());				
		}
		else if ( rd->getType() == DT_STRING ) {
			StringDecl* cd = static_cast<StringDecl*>(rd);
			if ( cd->getName() == "texture" ) {
				Texture* tex = gEngine->getResourceManager().getTextureByName(cd->getValue().c_str());
				shader.setTexture("gTex",tex);
			}			
		}
		if ( rd->getType() == DT_INT ) {
			IntDecl* fd = static_cast<IntDecl*>(rd);
			if ( fd->getName() == "material_texture" ) {
				ds::Material* m = gEngine->getResourceManager().getMaterialByName(m_Material.c_str());
				shader.setTexture("gTex",m->getTexture(fd->getValue()));	
			}
		}		
	}
}

void ShaderParser::createResource(ResourceDeclaration* declaration) {
	ShaderDecl* decl = static_cast<ShaderDecl*>(declaration);
	decl->createResource();	
}

void ShaderParser::loadTextFile(const ResourceFile& resourceFile,DeclarationManager* declarationManager) {
	JSONReader reader;
	if ( reader.parse(resourceFile.fqName.c_str()) ) {
		std::vector<Category*> categories = reader.getCategories();
		for ( size_t i = 0; i < categories.size(); ++i ) {
			Category* c = categories[i];
			if ( c->getName() == "shader") {
				ResourceDeclaration* decl = parseCategory(c);
				if ( decl != 0 ) {
					declarationManager->addDeclaration(decl);
				}
			}
		}
	}
}

ResourceDeclaration* ShaderParser::parseCategory(Category* category) {
	if ( category->hasProperty("name") ) {					
		std::string name = category->getProperty("name");
		LOGC(logINFO,"ShaderParser") << "Parsing shader definition " << name;
		std::string material = category->getProperty("material");
		std::string file = category->getProperty("file");
		std::string technique = category->getProperty("technique");					
		ShaderDecl* decl = new ShaderDecl(name,material,file,technique);
		if ( category->hasProperty("texture")) {
			decl->setTexture(category->getProperty("texture"));
		}					
		std::vector<Category*> sub = category->getChildren();
		for ( size_t c = 0; c < sub.size(); ++c ) {
			Category* sc = sub[c];
			if ( sc->getName() == "parameter" ) {
				std::string pName = sc->getProperty("name");
				std::string pType = sc->getProperty("type");
				if ( pType == "float" ) {
					float value = sc->read<float>("value",0.0f);
					FloatDecl* fd = new FloatDecl(name,value);
					decl->addParameter(fd);
				}
				else if ( pType == "Vec3" ) {
					Vec3 v = sc->getVec3("value");
					Vec3Decl* vd = new Vec3Decl(name,v);
					decl->addParameter(vd);
				}
				else if ( pType == "color" ) {
					Color c = sc->getColor("value");
					ColorDecl* cd = new ColorDecl(name,c);
					decl->addParameter(cd);
				}
				else if ( pType == "texture" ) {
					std::string tex = sc->getProperty("value");
					StringDecl* sd = new StringDecl("texture",tex);
					decl->addParameter(sd);								
				}	
				else if ( pType == "material_texture" ) {
					int idx = sc->read<int>("value",0);
					IntDecl* id = new IntDecl("material_texture",idx);
					decl->addParameter(id);
				}	
			}
		}
		return decl;
	}
	else {
		LOG(logERROR) << "missing name property detected";
	}
}

ResourceDeclaration* ShaderParser::loadTextFile(const ResourceFile& resourceFile) {	
	return 0;
}

}
